home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Applications / Welcome 1.3.1 / Welcome.c < prev    next >
Text File  |  1993-08-25  |  16KB  |  593 lines

  1. /*    Welcome!
  2.  
  3.     Welcome is an recreation of the Welcome2 application using the new Speech Manager.
  4. I have no connection with the original author, except fond memories. :-)
  5.  
  6. Copyright 1993 by Garrett Fitzgerald
  7. A product of donnael Software
  8.  
  9. v1.3    -    Menu selection of future default voice works!     -    8/25/93
  10. v1.2    -    Show speaking voice        -    8/22/93
  11.             Error alerts
  12.             Gestalt now works, with inclusion of <GestaltEqu.h>
  13.             Lists voices
  14.             Added about box
  15.             Defaults to "Female Voice", if available
  16. v1.1.1    -    Increased app partition to permit more complicated voices    -    8/16/93
  17.             Changed to StopSpeechAt end of word
  18.             Added commas after weekday
  19.             Re-did Finder icon
  20. v1.1    -    Added WaitNextEvent to allow quitting    -    8/16/93
  21. v1.0    -    initial release    -    8/15/93
  22. */
  23.  
  24. #include "Welcome.h"
  25. short vol_refnum,
  26.       prefs_file_refnum;
  27.  
  28. /*    toolbox_init()
  29.     
  30.     Initializes the full toolbox--things here seem to depend on it.
  31. */
  32.  
  33. toolbox_init()
  34. {
  35.  
  36.     InitGraf(&thePort);    
  37.     InitFonts();
  38.     InitWindows();
  39.     InitMenus();
  40.     TEInit();
  41.     InitDialogs(nil);
  42.     InitCursor();
  43. }
  44.  
  45. /*    prefs_init()
  46.     
  47.     Finds the Welcome! preferences file, or creates a new one. Returns true if file
  48. exists, false if the prefs folder can't be found or the file can't be opened.
  49. */
  50.  
  51. Boolean
  52. prefs_init()
  53.  
  54. {
  55.     OSErr err;
  56.     StringHandle vol_name;
  57.     long prefs_dir;
  58.     FSSpec prefs_spec;
  59.     Handle voice_res;
  60.     VoiceSpec init_voice_res;
  61.     extern short prefs_file_refnum,
  62.                  vol_refnum;
  63.     
  64.     vol_name = NewString("\p");
  65.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  66.                      &vol_refnum, &prefs_dir);
  67.     if (err != noErr)
  68.         return false;
  69.     
  70.     err = FSMakeFSSpec(vol_refnum, prefs_dir, PREFS_FILE_NAME, &prefs_spec);
  71.     
  72.     if (err == fnfErr) {
  73.         FSpCreateResFile(&prefs_spec, 'GSFC', 'pref', smSystemScript);
  74.         err = ResError();
  75.         if (err != noErr) {
  76.             FSpDelete(&prefs_spec);
  77.             return false;
  78.         }
  79.         prefs_file_refnum = FSpOpenResFile(&prefs_spec, fsRdWrPerm);
  80.         err = ResError();
  81.         if (err != noErr) {
  82.             FSpDelete(&prefs_spec);
  83.             return false;
  84.         }
  85.         
  86.         init_voice_res.creator = '????';
  87.         init_voice_res.id = '????';
  88.         PtrToHand((Ptr)&init_voice_res, &voice_res, sizeof(VoiceSpec));
  89.         AddResource(voice_res, VOICE_RES_TYPE, VOICE_RES_NUMB, "\pPreferred voice");
  90.         WriteResource(voice_res);
  91.         FlushVol(*vol_name, vol_refnum);
  92.     }
  93.     else {
  94.         prefs_file_refnum = FSpOpenResFile(&prefs_spec, fsRdWrPerm);
  95.         err = ResError();
  96.         if (err != noErr) {
  97.             return false;
  98.         }
  99.     }
  100. }
  101.  
  102. /*    date_to_text()
  103.  
  104.     Converts the numbers returned in Secs2Date to more readable months, days, time, and
  105. days of the week.
  106. */
  107.  
  108. void
  109. date_to_text(StringHandle *month, StringHandle *day, StringHandle *weekday, 
  110.              StringHandle *time, StringHandle *greeting)
  111. {
  112.     long secs,
  113.          mil_time;
  114.     Str255 hmin;
  115.     DateTimeRec now;
  116.          
  117.     GetDateTime(&secs);
  118.     IUTimeString(secs, false, hmin);    /* 4:22 AM */
  119.     *(hmin+*hmin+1) = '%';                /* Stick in a % for Munger to find later */
  120.     *hmin += 1;                            /* and fix the length byte... */
  121.     *time = NewString(hmin);
  122.     mil_time = Munger(time, 5, "M", 1, ".M.", 3);    /* If this is 12 hour time, change */
  123.     if (mil_time >= 0)                                /* AM/PM to A.M./P.M. */
  124.         **time += 2;                    /* Length byte again... */
  125.     
  126.     Secs2Date(secs, &now);                /* Turn the seconds since 1904 into a date/time record */
  127.     switch (now.dayOfWeek) {            /* Change the day of week, month, and date into words */
  128.         case 1:
  129.             *weekday = NewString("\pSunday, %");    /* and stick in a % for Munger to find later... */
  130.             break;
  131.         case 2:
  132.             *weekday = NewString("\pMonday, %");
  133.             break;
  134.         case 3:
  135.             *weekday = NewString("\pTuesday, %");
  136.             break;
  137.         case 4:
  138.             *weekday = NewString("\pWednesday, %");
  139.             break;
  140.         case 5:
  141.             *weekday = NewString("\pThursday, %");
  142.             break;
  143.         case 6:
  144.             *weekday = NewString("\pFriday, %");
  145.             break;
  146.         case 7:
  147.             *weekday = NewString("\pSaturday, %");
  148.             break;
  149.     }
  150.     switch (now.month) {
  151.         case 1:
  152.             *month = NewString("\pJanuary %");
  153.             break;
  154.         case 2:
  155.             *month = NewString("\pFebruary %");
  156.             break;
  157.         case 3:
  158.             *month = NewString("\pMarch %");
  159.             break;
  160.         case 4:
  161.             *month = NewString("\pApril %");
  162.             break;
  163.         case 5:
  164.             *month = NewString("\pMay %");
  165.             break;
  166.         case 6:
  167.             *month = NewString("\pJune %");
  168.             break;
  169.         case 7:
  170.             *month = NewString("\pJuly %");
  171.             break;
  172.         case 8:
  173.             *month = NewString("\pAugust %");
  174.             break;
  175.         case 9:
  176.             *month = NewString("\pSeptember %");
  177.             break;
  178.         case 10:
  179.             *month = NewString("\pOctober %");
  180.             break;
  181.         case 11:
  182.             *month = NewString("\pNovember %");
  183.             break;
  184.         case 12:
  185.             *month = NewString("\pDecember %");
  186.             break;
  187.     }
  188.     switch (now.day) {
  189.         case 1:
  190.             *day = NewString("\pfirst %");
  191.             break;
  192.         case 2:
  193.             *day = NewString("\psecond %");
  194.             break;
  195.         case 3:
  196.             *day = NewString("\pthird %");
  197.             break;
  198.         case 4:
  199.             *day = NewString("\pfourth %");
  200.             break;
  201.         case 5:
  202.             *day = NewString("\pfifth %");
  203.             break;
  204.         case 6:
  205.             *day = NewString("\psixth %");
  206.             break;
  207.         case 7:
  208.             *day = NewString("\pseventh %");
  209.             break;
  210.         case 8:
  211.             *day = NewString("\peighth %");
  212.             break;
  213.         case 9:
  214.             *day = NewString("\pnineth %");
  215.             break;
  216.         case 10:
  217.             *day = NewString("\ptenth %");
  218.             break;
  219.         case 11:
  220.             *day = NewString("\peleventh %");
  221.             break;
  222.         case 12:
  223.             *day = NewString("\ptwelveth %");
  224.             break;
  225.         case 13:
  226.             *day = NewString("\pthirteenth %");
  227.             break;
  228.         case 14:
  229.             *day = NewString("\pfourteenth %");
  230.             break;
  231.         case 15:
  232.             *day = NewString("\pfifteenth %");
  233.             break;
  234.         case 16:
  235.             *day = NewString("\psixteenth %");
  236.             break;
  237.         case 17:
  238.             *day = NewString("\pseventeenth %");
  239.             break;
  240.         case 18:
  241.             *day = NewString("\peighteenth %");
  242.             break;
  243.         case 19:
  244.             *day = NewString("\pnineteenth %");
  245.             break;
  246.         case 20:
  247.             *day = NewString("\ptwentieth %");
  248.             break;
  249.         case 21:
  250.             *day = NewString("\ptwenty-first %");
  251.             break;
  252.         case 22:
  253.             *day = NewString("\ptwenty-second %");
  254.             break;
  255.         case 23:
  256.             *day = NewString("\ptwenty-third %");
  257.             break;
  258.         case 24:
  259.             *day = NewString("\ptwenty-fourth %");
  260.             break;
  261.         case 25:
  262.             *day = NewString("\ptwenty-fifth %");
  263.             break;
  264.         case 26:
  265.             *day = NewString("\ptwenty-sixth %");
  266.             break;
  267.         case 27:
  268.             *day = NewString("\ptwenty-seventh %");
  269.             break;
  270.         case 28:
  271.             *day = NewString("\ptwenty-eighth %");
  272.             break;
  273.         case 29:
  274.             *day = NewString("\ptwenty-ninth %");
  275.             break;
  276.         case 30:
  277.             *day = NewString("\pthirtieth %");
  278.             break;
  279.         case 31:
  280.             *day = NewString("\pthirty-first %");
  281.             break;
  282.     }
  283.     
  284.     /* Go though and look for holidays -- specific date */
  285.     if ((now.month == 1) & (now.day == 1))
  286.         *greeting = NewString("\pHappy New Year! %");
  287.     else if ((now.month == 2) & (now.day == 14))
  288.         *greeting = NewString("\pHappy Valentine's Day! %");
  289.     else if ((now.month == 3) & (now.day == 17))
  290.         *greeting = NewString("\pHappy Saint Patrick's Day! %");
  291.     else if ((now.month == 3) & (now.day == 19))
  292.         *greeting = NewString("\pHappy Saint Joseph's Day! %");    /* I want a zeppola! */
  293.     else if ((now.month == 6) & (now.day == 14))
  294.         *greeting = NewString("\pHappy Flag Day! %");
  295.     else if ((now.month == 7) & (now.day == 4))
  296.         *greeting = NewString("\pHappy Independence Day! %");
  297.     else if ((now.month == 10) & (now.day == 12))
  298.         *greeting = NewString("\pHappy Columbus Day! %");
  299.     else if ((now.month == 11) & (now.day == 11))
  300.         *greeting = NewString("\pHappy Veterans Day! %");
  301.     else if ((now.month == 12) & (now.day == 25))
  302.         *greeting = NewString("\pMerry Chrismas! %");
  303.     
  304.     /* Now find 2nd Monday, 4th Thursday, etc. */
  305.     else if ((now.month == 2) & (now.day >= 9) & (now.day <= 15) & (now.dayOfWeek = 2))
  306.         *greeting = NewString("\pHappy Presidents' Day! %");
  307.     else if ((now.month == 5) & (now.day >= 8) & (now.day <= 14) & (now.dayOfWeek = 1))
  308.         *greeting = NewString("\pHappy Mother's Day! %");
  309.     else if ((now.month == 6) & (now.day >= 15) & (now.day <= 21) & (now.dayOfWeek = 1))
  310.         *greeting = NewString("\pHappy Father's Day! %");
  311.     else if ((now.month == 9) & (now.day >= 1) & (now.day <= 7) & (now.dayOfWeek = 2))
  312.         *greeting = NewString("\pHappy Labor Day! %");
  313.     else if ((now.month == 11) & (now.day >= 22) & (now.day <= 28) & (now.dayOfWeek = 5))
  314.         *greeting = NewString("\pHappy Thanksgiving! %");
  315.     
  316.     /* Evening before holidays... */
  317.     else if ((now.month == 12) & (now.day == 31) & (now.hour >= 18))
  318.         *greeting = NewString("\pit's New Year's Eve! %");
  319.     else if ((now.month == 12) & (now.day == 25) & (now.hour >= 18))
  320.         *greeting = NewString("\pit's Chrismas Eve! %");
  321.     
  322.     /* If it's not a holiday, then... */
  323.     else if ((now.hour >= 0) & (now.hour <= 4))
  324.         *greeting = NewString("\pyou should be in bed! %");
  325.     else if ((now.hour >= 5) & (now.hour <= 11))
  326.         *greeting = NewString("\pgood morning. %");
  327.     else if ((now.hour >= 12) & (now.hour <= 17))
  328.         *greeting = NewString("\pgood afternoon. %");
  329.     else if ((now.hour >= 18) & (now.hour <= 23))
  330.         *greeting = NewString("\pgood evening. %");
  331. }
  332.  
  333. Boolean
  334. handle_menus(long menu_choice, Boolean prefs)
  335. {    
  336.     static int checked_voice = 0;
  337.     short menu,
  338.           choice;
  339.     Str255 da_name;
  340.     MenuHandle voice_menu;
  341.     VoiceSpec voice;
  342.     Handle voice_res,
  343.            voice_hand;
  344.     OSErr err;
  345.     
  346.     menu = HiWord(menu_choice);
  347.     choice = LoWord(menu_choice);
  348.     
  349.     switch (menu) {
  350.         case MENU_APPLE:
  351.             switch (choice) {
  352.                 case 1:                /* About Branagh */
  353.                     Alert(ALRT_ABOUT, nil);
  354.                     break;
  355.                 default:            /* DAs */
  356.                     GetItem(GetMHandle(MENU_APPLE), choice, da_name);
  357.                     OpenDeskAcc(da_name);
  358.                     break;
  359.             }
  360.             break;
  361.         case MENU_FILE:
  362.             if (choice == FILE_QUIT) 
  363.                 return true;
  364.             break;
  365.         case MENU_VOICES:
  366.             if ((prefs = true) && (choice != 0)) {
  367.                 voice_menu = GetMHandle(MENU_VOICES);
  368.                 if (checked_voice != 0)
  369.                     CheckItem(voice_menu, checked_voice, false);
  370.                 CheckItem(voice_menu, choice, true);
  371.                 GetIndVoice(choice, &voice);
  372.                 voice_res = GetResource(VOICE_RES_TYPE, VOICE_RES_NUMB);
  373.                 PtrToXHand((Ptr)&voice, voice_res, sizeof(VoiceSpec));
  374.                 ChangedResource(voice_res);
  375.                 err = ResError();
  376.                 if (err != noErr)
  377.                     SysBeep(20);
  378.             }
  379.             break;
  380.     }
  381.     return false;
  382. }
  383.  
  384. stop_speech(SpeechChannel channel)
  385. {
  386.     OSErr err;
  387.     
  388.     err = StopSpeechAt(channel, kEndOfWord);
  389.     if (err != noErr)
  390.         SysBeep(20);
  391.     while (SpeechBusy() > 0);
  392. }
  393.  
  394. main()
  395. {
  396.     long info,
  397.          ticks,
  398.          menu_choice;
  399.     int i;
  400.     Boolean done = false,
  401.             prefs;
  402.     EventRecord choice;
  403.     short index;
  404.     StringHandle month,
  405.                  day,
  406.                  weekday,
  407.                  time,
  408.                  greeting,
  409.                  text;
  410.     OSErr err;
  411.     VoiceSpec voice;
  412.     VoiceDescription voice_info;
  413.     SpeechChannel channel;
  414.     DialogPtr voice_dlog;
  415.     Handle menu_bar,
  416.            default_voice;
  417.     MenuHandle menu,
  418.                voice_menu;
  419.     Point where;
  420.     WindowPtr which_window;
  421.     Boolean galatea = false;
  422.     extern short prefs_file_refnum,
  423.                  vol_refnum;
  424.     
  425.     toolbox_init();
  426.     FlushEvents(everyEvent, 0);
  427.     prefs = prefs_init();
  428.     
  429.     menu_bar = GetNewMBar(MENU_BAR);            /* Set up menus... */
  430.     if (menu_bar == nil) {
  431.         SysBeep(20);
  432.         return;
  433.     }
  434.     else 
  435.         SetMenuBar(menu_bar);
  436.         
  437.     menu = GetMHandle(MENU_APPLE);
  438.     AddResMenu(menu, 'DRVR');
  439.     
  440.     err = Gestalt(gestaltSpeechAttr, &info);
  441.     if (err == gestaltUndefSelectorErr) {
  442.         ParamText("\pWelcome! requires that the Speech Manager be installed. Sorry.", "\p", "\p", "\p");
  443.         StopAlert(ALRT_ERR, nil);
  444.         SysBeep(20);
  445.         return;
  446.     }
  447.     else if (err != noErr) {
  448.         ParamText("\pProblem calling Gestalt: exiting.", "\p", "\p", "\p");
  449.         StopAlert(ALRT_ERR, nil);
  450.         SysBeep(20);
  451.         return;
  452.     }
  453.     
  454.     if (!(info && (1L << gestaltSpeechMgrPresent))) {
  455.         ParamText("\pWelcome! requires that the Speech Manager be installed. Sorry.", "\p", "\p", "\p");
  456.         StopAlert(ALRT_ERR, nil);
  457.         SysBeep(20);
  458.         return;
  459.     }
  460.  
  461.     err = CountVoices(&index);            /* How many voices do we have? */
  462.     if (err != noErr) {
  463.         ParamText("\pI really don't think there should have been an error here...", "\p", "\p", "\p");
  464.         StopAlert(ALRT_ERR, nil);
  465.         SysBeep(20);
  466.         return;
  467.     }
  468.  
  469.     voice_menu = GetMHandle(MENU_VOICES);
  470.     for (i = 1; i <= index; i++) {
  471.         err = GetIndVoice(i, &voice);
  472.         if (err != noErr) {
  473.             ParamText("\pCouldn't find indicated voice. Exiting.", "\p", "\p", "\p");
  474.             StopAlert(ALRT_ERR, nil);
  475.             SysBeep(20);
  476.             return;
  477.         }
  478.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  479.         AppendMenu(voice_menu, voice_info.name);
  480.         if ((voice.creator == 'gala') && (voice.id == 12))    /* If "Female voice" is available,*/
  481.             galatea = true;                                    /* use it, unless overruled */
  482.     }
  483.     
  484.     DrawMenuBar();
  485.     
  486.     default_voice = GetResource(VOICE_RES_TYPE, VOICE_RES_NUMB);
  487.     HLock(default_voice);
  488.     if (((VoiceSpec *)*default_voice)->creator != '????') {
  489.         voice.creator = ((VoiceSpec *)*default_voice)->creator;
  490.         voice.id = ((VoiceSpec *)*default_voice)->id;
  491.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  492.         galatea = false;
  493.     }
  494.     HUnlock(default_voice);
  495.     
  496.     if (galatea) {
  497.         voice.creator = 'gala';
  498.         voice.id = (long)12;
  499.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  500.     }
  501.     
  502.     err = NewSpeechChannel(&voice, &channel);    /* Open a SpeechChannel */
  503.     if (err == synthOpenFailed) {
  504.         ParamText("\pCould not open SpeechChannel: Try increasing the memory partition.", "\p", "\p", "\p");
  505.         StopAlert(ALRT_ERR, nil);
  506.         return;
  507.     }
  508.     else if (err != noErr) {
  509.         ParamText("\pCould not open SpeechChannel: exiting.", "\p", "\p", "\p");
  510.         StopAlert(ALRT_ERR, nil);
  511.         SysBeep(20);
  512.         return;
  513.     }
  514.     
  515.     ParamText(voice_info.name, "\p", "\p", "\p");
  516.     voice_dlog = GetNewDialog(DLOG_VOICE, nil, WINDOW_IN_FRONT);
  517.     if (voice_dlog == nil) {
  518.         ParamText("\pCan't show current voice...", "\p", "\p", "\p");
  519.         StopAlert(ALRT_ERR, nil);
  520.     }
  521.     ShowWindow(voice_dlog);
  522.     DrawDialog(voice_dlog);
  523.     
  524.     date_to_text(&month, &day, &weekday, &time, &greeting);
  525.     
  526.     /* Plug everything into one long string... */
  527.     text = NewString("\pWelcome to Mackintosh, and %");
  528.     SetHandleSize(text, sizeof(Str255));
  529.     Munger(text, 1, "%", 1, *greeting+1, **greeting);     /* Find the %, and replace it with */
  530.     **text = **text + **greeting - 1;                    /* the next part of the string... */
  531.     Munger(text, 1, "%", 1, "It's %", 6);
  532.     **text = **text + 5;                                /* Fix the length byte, ignoring the */
  533.     Munger(text, 1, "%", 1, *weekday+1, **weekday);        /* length byte from the replacement string*/
  534.     **text = **text + **weekday - 1;                    /* (it got cut out, *weekday+1, anyway) */
  535.     Munger(text, 1, "%", 1, *month+1, **month);
  536.     **text = **text + **month - 1;
  537.     Munger(text, 1, "%", 1, *day+1, **day);
  538.     **text = **text + **day - 1;
  539.     Munger(text, 1, "%", 1, "at %", 4);
  540.     **text = **text + 3;
  541.     Munger(text, 1, "%", 1, *time + 1, **time);
  542.     **text = **text + **time - 1;
  543.     Munger(text, 1, "%", 1, ". Let's go!", 11);
  544.     **text = **text + 10;
  545.     
  546.     MoveHHi(text);
  547.     HLock(text);
  548.     SpeakText(channel, (Ptr)(*text + 1), **text);        /* Then speak the text through the channel */
  549.                                                         /* we got up top... */
  550.     while(!done) {
  551.         WaitNextEvent((mDownMask | keyDownMask), &choice, 15, nil);
  552.         switch (choice.what) {
  553.             case mouseDown:
  554.                 where = choice.where;
  555.                 switch (FindWindow(where, &which_window)) {
  556.                     case inMenuBar:
  557.                         menu_choice = MenuSelect(where);
  558.                         if (HiWord(menu_choice) != 0) {
  559.                             done = handle_menus(menu_choice, prefs);
  560.                             if (done == true)
  561.                                 stop_speech(channel);
  562.                         }
  563.                         HiliteMenu(0);
  564.                         break;
  565.                     default:
  566.                         stop_speech(channel);
  567.                         done = true;
  568.                         break;
  569.                 }
  570.                 break;
  571.             case keyDown:
  572.                 stop_speech(channel);
  573.                 done = true;
  574.                 break;
  575.         }
  576.         if (SpeechBusy() == 0)
  577.             done = true;
  578.     }
  579.     
  580.     HUnlock(text);    
  581.     
  582.     DisposeSpeechChannel(channel);                        /* And clean up. */
  583.     DisposeDialog(voice_dlog);
  584.     DisposeHandle(month);
  585.     DisposeHandle(day);
  586.     DisposeHandle(weekday);
  587.     DisposeHandle(greeting);
  588.     DisposeHandle(text);
  589.     DisposeHandle(time);
  590.     CloseResFile(prefs_file_refnum);
  591.     FlushVol(NewString("\p"), vol_refnum);
  592. }
  593.